package com.zh.demo02.verifycode;

import com.zh.demo02.util.RandomCodeUtil;
import com.zh.demo02.verifycode.sms.SmsCode;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;


/**
 * @author ZH
 * @Date 20:39 2020/4/15
 */
public abstract class VerifyCodeService {
    /**验证码的 session key*/
    static final String SESSION_KEY_VERIFY_CODE = "session_key:verifyCode";

    private static final VerifyCode noneCode = new NoneCode();

    /**
     * 验证码的长度
     */
    protected int codeLength;
    /**
     * 验证码的有效时间
     */
    protected int expireSecond;

    /**
     * 请求验证码
     */
    final public void createAndSend(HttpServletRequest request, HttpServletResponse response) {
        var phone = request.getParameter("phone");
        if(phone==null || phone.isEmpty())
            throw new IllegalArgumentException("手机号不能为空");

        //生成验证码
        VerifyCode code = new SmsCode(RandomCodeUtil.getNumberCode(this.codeLength), this.expireSecond,phone);

        this.store(request, code);

        //发送验证码
        try {
            this.sendCode(code, response);
        } catch (IOException e) {
            System.err.println("发送验证码失败 " + e.getMessage());
        }
    }



    final public void store(HttpServletRequest request, VerifyCode code){
        //存储验证码到session中
        request.getSession().setAttribute(SESSION_KEY_VERIFY_CODE, code);
    }

    /**
     * 获取验证码
     */
    @NotNull
    final public VerifyCode getVerificationCode(HttpServletRequest request) {
        Object attribute = request.getSession().getAttribute(SESSION_KEY_VERIFY_CODE);
        return attribute == null ? noneCode : (VerifyCode) attribute;
    }

    /**
     * 发送验证码
     */
    protected abstract void sendCode(VerifyCode verifyCode, HttpServletResponse response) throws IOException;


    /**
     * 核对验证码
     * @param request HttpServletRequest
     * @param codeValue 验证码值
     * @throws VerificationCodeFailException 验证码校验失败异常
     */
    public void validate(HttpServletRequest request,String codeValue) {

        VerifyCode verifyCode = this.getVerificationCode(request);

        if (codeValue==null || codeValue.isEmpty())
            throw new VerificationCodeFailException("验证码为空");

        if(verifyCode instanceof NoneCode || verifyCode.isExpire())
            throw new VerificationCodeFailException("验证码已失效");

        if (!verifyCode.getCode().equalsIgnoreCase(codeValue))
            throw new VerificationCodeFailException("验证码错误");

        //清除验证码到session中
        request.getSession().removeAttribute(SESSION_KEY_VERIFY_CODE);
    }
}
